package com.aggregate.pay.lianlianpay.support;

import java.util.HashMap;
import java.util.Map;

import com.aggregate.pay.lianlianpay.bean.AbstractData;
import com.aggregate.pay.lianlianpay.bean.AbstractResult;
import com.aggregate.pay.lianlianpay.support.utils.JSON;
import com.lianlianpay.security.utils.LianLianPaySecurity;

/**
 * 银盈通代付接口API操作类抽象类
 * @author Moyq5
 * @date 2019年3月14日
 * @param <D>
 * @param <R>
 */
public abstract class AbstractClient<D extends AbstractData, R extends AbstractResult> implements Client<D, R> {
		
	private Merch merch;
	
	public AbstractClient(Merch merch) {
		this.merch = merch;
	}
	
	@Override
	public R execute(D data) {
		data.setApiVersion("1.0");
		data.setOidPartner(merch.merchNo());
		//data.setPlatform(platform);
		data.setSignType("RSA");
		
		R result = null;
		try {
			String sign = Tool.sign(data, merch.privateKey());
			data.setSign(sign);
			
			String reqJson = JSON.toString(data);
			log.debug("加密明文：{}", reqJson);
			if (isEncrypt()) {
				Map<String, String> map = new HashMap<>();
				map.put("oid_partner", merch.merchNo());
				map.put("pay_load", LianLianPaySecurity.encrypt(reqJson, Factory.getConfig().publicKey()));
				reqJson = JSON.toString(map);
			}
			
			String resJson = Factory.getHttpClient().post(serverPath(), reqJson);
			
			result = JSON.toObject(resJson, resultClass());
			
			if (result.getRetCode().equals("0000") && !Tool.verify(Tool.toQueryString(resJson), result.getSign(), Factory.getConfig().publicKey())) {
				throw new Exception("未通过验签");
			}
			
			return result;
			
		} catch (Exception e) {
			log.error("接口调用失败", e);
			try {
				result = resultClass().newInstance();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			result.setRetCode("C9999");
			result.setRetMsg("本地错误：" + e.getMessage());
		}
		return result;
	}
	
	protected String serverPath() {
		return Factory.getConfig().serverPath();
	}

	protected abstract boolean isEncrypt();
	protected abstract Class<R> resultClass();
}
